package com.fire.controller;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.apistd.uni.Uni;
import com.apistd.uni.UniException;
import com.apistd.uni.UniResponse;
import com.apistd.uni.sms.UniMessage;
import com.apistd.uni.sms.UniSMS;
import com.fire.constant.RedisConstant;
import com.fire.exception.ServiceException;
import com.fire.model.entity.Location;
import com.fire.model.entity.Machine;
import com.fire.model.entity.Monitor;
import com.fire.response.ResponseCodeEnum;
import com.fire.response.ResultData;
import com.fire.service.*;
import com.fire.utils.RandomNumberUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author author
 * @since 2024-03-27
 */
@Slf4j
@Validated
@CrossOrigin
@RestController
@RequiredArgsConstructor
@Api(tags = {"公共模块"})
@RequestMapping("/common")
public class CommonController {

    private final IMachineService machineService;
    private final IMonitorService monitorService;
    private final ILocationService locationService;
    private final IAsyncService asyncService;

    /**
     * 导出机器数据
     * @param response
     * @throws IOException
     */
    @GetMapping("/export")
    @ApiOperation(value = "导出机器数据")
    public void export(HttpServletResponse response) throws IOException {
        log.info("开始导出机器数据---------");
        long beginTime = System.currentTimeMillis();
        //从数据库查询出所有的数据
        List<Machine> list = machineService.list();
        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.write(list,true);

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("机器管理数据","UTF-8");
        response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx");

        ServletOutputStream out = response.getOutputStream();
        writer.flush(out,true);
        out.close();
        writer.close();
        long endTime = System.currentTimeMillis();
        log.info("导出机器数据结束-----,消耗：{}ms",(endTime-beginTime));
    }

    /**
     * TODO: 导入机器数据(模拟机器上传自身状态数据)
     * @throws IOException
     */
    @PostMapping("/import")
    @ApiOperation(value = "导入机器数据")
    public ResultData machineDataImport(MultipartFile file) throws IOException, ServiceException {
        log.info("开始导入机器数据---------");
        long beginTime = System.currentTimeMillis();
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        //方式(1): 通过javabean的方式读取Excel内的对象，但是要求表头必须是英文，跟javabean的属性要对应起来
        List<Machine> lists = reader.readAll(Machine.class);
        if(!CollectionUtils.isEmpty(lists)){
            //TODO: 模拟机器提交自身数据：插入的同时将故障机器的编号使用集合存起来，发送短信通知管理员
            List<String> machineIds = lists.stream()
                    .filter(machine -> machine.getStatus().getDescription().equalsIgnoreCase("故障"))
                    .map(machine -> machine.getMachineId()).collect(Collectors.toList());
            machineService.saveBatch(lists);
            long endTime = System.currentTimeMillis();
            log.info("导入机器数据结束-----,消耗：{}ms",(endTime-beginTime));
            if(!CollectionUtils.isEmpty(machineIds)){
                //说明有故障机器的数据
                asyncService.sendMachineMail(machineIds + "");
            }
        }
        return ResultData.success();
    }

    /**
     * 导出监测数据
     * @param response
     * @throws IOException
     */
    @GetMapping("/monitor/export")
    @ApiOperation(value = "导出监测数据")
    public void MonitorExport(HttpServletResponse response) throws IOException {
        log.info("开始导出监测数据---------");
        long beginTime = System.currentTimeMillis();
        //从数据库查询出所有的数据
        List<Monitor> list = monitorService.list();
        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.write(list,true);

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("监测数据","UTF-8");
        response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx");

        ServletOutputStream out = response.getOutputStream();
        writer.flush(out,true);
        out.close();
        writer.close();
        long endTime = System.currentTimeMillis();
        log.info("导出监测数据结束-----,消耗：{}ms",(endTime-beginTime));
    }

    /**
     * TODO: 导入机器监测数据(模拟机器上传环境监测数据)
     * @throws IOException
     */
    @PostMapping("/monitor/import")
    @ApiOperation(value = "导入监测数据")
    public ResultData monitorDataImport(MultipartFile file) throws IOException {
        log.info("开始导入监测数据---------");
        long beginTime = System.currentTimeMillis();
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        //方式(1): 通过javabean的方式读取Excel内的对象，但是要求表头必须是英文，跟javabean的属性要对应起来
        List<Monitor> lists = reader.readAll(Monitor.class);
        if(!CollectionUtils.isEmpty(lists)){
            //TODO: 模拟机器提交监测数据：发送短信通知管理员
            List<Monitor> warnMonitors = lists.stream()
                    .filter(monitor -> monitor.getStatus().getDescription().equalsIgnoreCase("警告"))
                    .collect(Collectors.toList());
            monitorService.saveBatch(lists);
            long endTime = System.currentTimeMillis();
            log.info("导入监测数据结束-----,消耗：{}ms",(endTime-beginTime));
            if(!CollectionUtils.isEmpty(warnMonitors)){
                //说明有警告状态的数据
                List<String> list = new ArrayList();
                warnMonitors.stream().forEach(item -> {
                    String content = "【机器编号：" + item.getMachineId() + "；"
                            + "位置：" + item.getLocation() + "】";
                    list.add(content);
                });
                //异步发送报警邮箱信息
                asyncService.sendMonitorMail(list + "");
                //异步往f_smart表中将异常数据的位置信息做记录
                asyncService.saveSmartInfo(warnMonitors);
            }
        }
        return ResultData.success();
    }

    /**
     * 导入主要城市数据
     * @throws IOException
     */
    @PostMapping("/location/import")
    @ApiOperation(value = "导入主要城市数据")
    public void locationDataImport(MultipartFile file) throws IOException {
        log.info("开始导入机器数据---------");
        long beginTime = System.currentTimeMillis();
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        //方式(1): 通过javabean的方式读取Excel内的对象，但是要求表头必须是英文，跟javabean的属性要对应起来
        List<Location> lists = reader.readAll(Location.class);

        locationService.saveBatch(lists);
        long endTime = System.currentTimeMillis();
        log.info("导入机器数据结束-----,消耗：{}ms",(endTime-beginTime));
    }

}
